package cn.com.cifi.mars.service.impl;

import cn.com.cifi.mars.bean.vo.returnPlan.SupervisoryConsoleVo;
import cn.com.cifi.mars.common.exception.MsgException;
import cn.com.cifi.mars.constant.CodeEnum;
import cn.com.cifi.mars.constant.HrOrgTypeEunm;
import cn.com.cifi.mars.constant.IsDeleteEnum;
import cn.com.cifi.mars.constant.LogEventEnum;
import cn.com.cifi.mars.entity.ReturnPlanVersion;
import cn.com.cifi.mars.entity.ReturnPlanVersionDetail;
import cn.com.cifi.mars.entity.SupervisoryConsoleReturnDetail;
import cn.com.cifi.mars.entity.common.ProjectByStages;
import cn.com.cifi.mars.mapper.mars.ProjectByStagesMapper;
import cn.com.cifi.mars.mapper.mars.ReturnPlanVersionDetailMapper;
import cn.com.cifi.mars.mapper.mars.SupervisoryConsoleReturnDetailMapper;
import cn.com.cifi.mars.mapper.wrapper.ReturnPlanVersionDetailWrapper;
import cn.com.cifi.mars.service.ReturnPlanVersionService;
import cn.com.cifi.mars.service.SupervisoryConsoleReturnDetailService;
import cn.com.cifi.mars.util.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * <p>
 * 监控台-回明细表 服务实现类
 * </p>
 *
 * @author JingYuanXiang
 * @since 2020-12-28
 */
@Service
public class SupervisoryConsoleReturnDetailServiceImpl extends ServiceImpl<SupervisoryConsoleReturnDetailMapper, SupervisoryConsoleReturnDetail> implements SupervisoryConsoleReturnDetailService {

    @Autowired
    private SupervisoryConsoleReturnDetailMapper supervisoryConsoleReturnDetailMapper;
    @Autowired
    private ProjectByStagesMapper projectByStagesMapper;
    @Autowired
    private ReturnPlanVersionService returnPlanVersionService;
    @Autowired
    private ReturnPlanVersionDetailWrapper returnPlanVersionDetailWrapper;

    /**
     * 生成监控台-回数据
     * @param yearMonth 年月
     */
    @Transactional
    @Override
    public void createReturn(String yearMonth) {
        if(StrUtils.isEmpty(yearMonth)){
            throw new MsgException(CodeEnum.REQUEST_PARAM_NOT_FULL_ERROR);
        }
        //获取当前年月时间
        LocalDateTime dateTime = LocalDateTimeUtils.toLocalDateTime(yearMonth);
        //获取年份
        int year = dateTime.getYear();
        //获取当年一月
        String yearFirstMonth = year + "-01";
        //获取前滚十二个月时间
        LocalDateTime minusTwelveTime = dateTime.minusMonths(12);
        //获取归属年月
        String affiliation = yearMonth.replace("-","");
        //获取组织机构表
        List<ProjectByStages> orgList = projectByStagesMapper.selectList(new QueryWrapper<>());
        //获取组织id与组织射关系
        Map<String,ProjectByStages> orgMap = orgList.stream().collect(Collectors.toMap(ProjectByStages::getOrgdepid, s->s));
        //获取截止指定年月全盘回款版本列表
        List<ReturnPlanVersion> allVersionList = returnPlanVersionService.getOverallVersionList(yearMonth);
        if(CollectionUtils.isEmpty(allVersionList)){
            return;
        }
        //获取回款版本id与回款版本归属时间映射关系
        Map<String, LocalDateTime> returnVersionAffiliationTimeMap = allVersionList.stream().collect(Collectors.toMap(ReturnPlanVersion::getId, s -> LocalDateTimeUtils.toLocalDateTime(s.getAffiliationMonth())));
        //获取回款版本id与项目id映射关系
        Map<String,String> projectIdMap = allVersionList.stream().collect(Collectors.toMap(ReturnPlanVersion::getId, ReturnPlanVersion::getProjectId));
        //查询回款详情列表
        List<ReturnPlanVersionDetail> returnPlanVersionDetailList = returnPlanVersionDetailWrapper.selectByVersionIdList(new ArrayList<>(returnVersionAffiliationTimeMap.keySet()), IsDeleteEnum.NO.getKey());
        //对回款详情列表以项目分组
        Map<String, List<ReturnPlanVersionDetail>> returnDetailListMap = returnPlanVersionDetailList.stream().collect(Collectors.groupingBy(s -> projectIdMap.get(s.getVersionId())));

        //计算项目数据
        List<SupervisoryConsoleVo> projectList = new ArrayList<>();
        for (Map.Entry<String, List<ReturnPlanVersionDetail>> projectReturnDetailListEntry: returnDetailListMap.entrySet()){
            //项目id
            String projectId = projectReturnDetailListEntry.getKey();
            if("56319688435".equals(projectId)){
                System.out.println(1);
            }
            //项目回款详情列表
            List<ReturnPlanVersionDetail> projectReturnDetailList = projectReturnDetailListEntry.getValue();
            //项目组织数据
            ProjectByStages org = orgMap.get(projectId);

            //计算年度签约合计
            BigDecimal yearSignAmount = projectReturnDetailList.stream()
                    .filter(s -> year == s.getReturnTime().getYear() && LocalDateTimeUtils.compareDate(s.getReturnTime(),returnVersionAffiliationTimeMap.get(s.getVersionId()),0))
                    .map(ReturnPlanVersionDetail::getActualSignAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            //计算年度回款合计
            BigDecimal yearReturnAmount = projectReturnDetailList.stream()
                    .filter(s -> year == s.getReturnTime().getYear() && LocalDateTimeUtils.compareDate(s.getReturnTime(),returnVersionAffiliationTimeMap.get(s.getVersionId()),0))
                    .map(ReturnPlanVersionDetail::getTotalReturnAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            //计算年初应收金额
            BigDecimal yearFirstMoney = projectReturnDetailList.stream()
                    .filter(s -> yearFirstMonth.equals(LocalDateTimeUtils.formatTime(s.getReturnTime(),DateUtils.DATE_JFP_STR)))
                    .map(ReturnPlanVersionDetail::getEarlyReceivableAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            //计算前滚十二个月签约金额
            BigDecimal minusTwelveSignAmount = projectReturnDetailList.stream()
                    .filter(s -> !LocalDateTimeUtils.compareDate(s.getReturnTime(),minusTwelveTime,0) && LocalDateTimeUtils.compareDate(s.getReturnTime(),returnVersionAffiliationTimeMap.get(s.getVersionId()),0))
                    .map(ReturnPlanVersionDetail::getActualSignAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            //计算前滚十二个月回款金额
            BigDecimal minusTwelveReturnAmount = projectReturnDetailList.stream()
                    .filter(s -> !LocalDateTimeUtils.compareDate(s.getReturnTime(),minusTwelveTime,0) && LocalDateTimeUtils.compareDate(s.getReturnTime(),returnVersionAffiliationTimeMap.get(s.getVersionId()),0))
                    .map(ReturnPlanVersionDetail::getTotalReturnAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            //计算前滚十二个月的应收金额
            BigDecimal minusTwelveReceivableAmount = projectReturnDetailList.stream()
                    .filter(s -> LocalDateTimeUtils.compareDate(s.getReturnTime(),minusTwelveTime,2))
                    .map(ReturnPlanVersionDetail:: getEarlyReceivableAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            //计算年度签约回款率 = 年度回款合计/年度签约合计
            BigDecimal yearSignReturnRate = BigDecimalUtils.divBigDecimal(yearReturnAmount,yearSignAmount,5).multiply(new BigDecimal(100));
            //计算年度综合回款率 = 年度回款合计/（年初应收+年度签约合计）
            BigDecimal yearOverallRate = BigDecimalUtils.divBigDecimal(yearReturnAmount,yearFirstMoney.add(yearSignAmount),5).multiply(new BigDecimal(100));
            //计算滚动综合回款率 = 前滚12月回款合计/（前滚12月应收+前滚12月签约合计）
            BigDecimal rollRate = BigDecimalUtils.divBigDecimal(minusTwelveReturnAmount,minusTwelveReceivableAmount.add(minusTwelveSignAmount),5).multiply(new BigDecimal(100));

            SupervisoryConsoleVo supervisoryConsoleVo = new SupervisoryConsoleVo();
            supervisoryConsoleVo.setYearSignAmount(yearSignAmount);
            supervisoryConsoleVo.setYearReturnAmount(yearReturnAmount);
            supervisoryConsoleVo.setYearFirstMoney(yearFirstMoney);
            supervisoryConsoleVo.setMinusTwelveSignAmount(minusTwelveSignAmount);
            supervisoryConsoleVo.setMinusTwelveReturnAmount(minusTwelveReturnAmount);
            supervisoryConsoleVo.setMinusTwelveReceivableAmount(minusTwelveReceivableAmount);
            supervisoryConsoleVo.setYearSignReturnRate(yearSignReturnRate);
            supervisoryConsoleVo.setYearOverallRate(yearOverallRate);
            supervisoryConsoleVo.setRollRate(rollRate);
            supervisoryConsoleVo.setOrgId(org.getOrgdepid());
            supervisoryConsoleVo.setOrgName(org.getOrgname());
            supervisoryConsoleVo.setAffiliation(affiliation);
            supervisoryConsoleVo.setHrOrgTypeId(org.getHrOrgTypeId());
            supervisoryConsoleVo.setParentOrgid(org.getParentOrgid());
            projectList.add(supervisoryConsoleVo);
        }

        //汇总计算城市数据
        List<SupervisoryConsoleVo> cityList = summaryData(orgList,projectList,affiliation);
        //汇总计算区域数据
        List<SupervisoryConsoleVo> businessList = summaryData(orgList,cityList, affiliation);
        //汇总计算集团数据
        List<SupervisoryConsoleVo> groupList = summaryData(orgList,businessList, affiliation);

        List<SupervisoryConsoleVo> allList = new ArrayList<>();
        allList.addAll(projectList);
        allList.addAll(cityList);
        allList.addAll(businessList);
        allList.addAll(groupList);

        //删除的数据
        supervisoryConsoleReturnDetailMapper.deleteByYearMonth(affiliation, IsDeleteEnum.NO.getKey());
        //写入数据
        supervisoryConsoleReturnDetailMapper.insertList(allList);
    }

    /**
     * 数据汇总
     * @param orgList
     * @param projectList
     * @param affiliation
     * @return
     */
    private List<SupervisoryConsoleVo> summaryData(List<ProjectByStages> orgList, List<SupervisoryConsoleVo> projectList, String affiliation) {
        Map<String, ProjectByStages> orgIdMap = orgList.stream().collect(Collectors.toMap(ProjectByStages::getOrgdepid, s->s));
        Map<String, List<SupervisoryConsoleVo>> consoleVoMap = projectList.stream().collect(Collectors.groupingBy(SupervisoryConsoleVo::getParentOrgid));

        List<SupervisoryConsoleVo> parentList = new ArrayList<>();
        for (Map.Entry<String, List<SupervisoryConsoleVo>> parentEntry : consoleVoMap.entrySet()){
            ProjectByStages org = orgIdMap.get(parentEntry.getKey());
            List<SupervisoryConsoleVo> consoleVoList = parentEntry.getValue();

            //计算年度签约合计
            BigDecimal yearSignAmount = BigDecimal.ZERO;
            //计算年度回款合计
            BigDecimal yearReturnAmount = BigDecimal.ZERO;
            //计算年初应收金额
            BigDecimal yearFirstMoney = BigDecimal.ZERO;
            //计算前滚十二个月签约金额
            BigDecimal minusTwelveSignAmount = BigDecimal.ZERO;
            //计算前滚十二个月回款金额
            BigDecimal minusTwelveReturnAmount = BigDecimal.ZERO;
            //计算前滚十二个月的应收金额
            BigDecimal minusTwelveReceivableAmount = BigDecimal.ZERO;
            for (SupervisoryConsoleVo consoleVo : consoleVoList){
                yearSignAmount = yearSignAmount.add(consoleVo.getYearSignAmount());
                yearReturnAmount = yearReturnAmount.add(consoleVo.getYearReturnAmount());
                yearFirstMoney = yearFirstMoney.add(consoleVo.getYearFirstMoney());
                minusTwelveSignAmount = minusTwelveSignAmount.add(consoleVo.getMinusTwelveSignAmount());
                minusTwelveReturnAmount = minusTwelveReturnAmount.add(consoleVo.getMinusTwelveReturnAmount());
                minusTwelveReceivableAmount = minusTwelveReceivableAmount.add(consoleVo.getMinusTwelveReceivableAmount());
            }
            //计算年度签约回款率 = 年度回款合计/年度签约合计
            BigDecimal yearSignReturnRate = BigDecimalUtils.divBigDecimal(yearReturnAmount,yearSignAmount,5).multiply(new BigDecimal(100));
            //计算年度综合回款率 = 年度回款合计/（年初应收+年度签约合计）
            BigDecimal yearOverallRate = BigDecimalUtils.divBigDecimal(yearReturnAmount,yearFirstMoney.add(yearSignAmount),5).multiply(new BigDecimal(100));
            //计算滚动综合回款率 = 前滚12月回款合计/（前滚12月应收+前滚12月签约合计）
            BigDecimal rollRate = BigDecimalUtils.divBigDecimal(minusTwelveReturnAmount,minusTwelveReceivableAmount.add(minusTwelveSignAmount),5).multiply(new BigDecimal(100));

            SupervisoryConsoleVo supervisoryConsoleVo = new SupervisoryConsoleVo();
            supervisoryConsoleVo.setYearSignAmount(yearSignAmount);
            supervisoryConsoleVo.setYearReturnAmount(yearReturnAmount);
            supervisoryConsoleVo.setYearFirstMoney(yearFirstMoney);
            supervisoryConsoleVo.setMinusTwelveSignAmount(minusTwelveSignAmount);
            supervisoryConsoleVo.setMinusTwelveReturnAmount(minusTwelveReturnAmount);
            supervisoryConsoleVo.setMinusTwelveReceivableAmount(minusTwelveReceivableAmount);
            supervisoryConsoleVo.setYearSignReturnRate(yearSignReturnRate);
            supervisoryConsoleVo.setYearOverallRate(yearOverallRate);
            supervisoryConsoleVo.setRollRate(rollRate);
            supervisoryConsoleVo.setOrgId(org.getOrgdepid());
            supervisoryConsoleVo.setOrgName(org.getOrgname());
            supervisoryConsoleVo.setAffiliation(affiliation);
            supervisoryConsoleVo.setHrOrgTypeId(org.getHrOrgTypeId());
            supervisoryConsoleVo.setParentOrgid(org.getParentOrgid());
            parentList.add(supervisoryConsoleVo);
        }
        return parentList;
    }
}
